<?php

namespace Commands;

use ReflectionClass;

trait GiiTrait
{


    /**
     * @param ReflectionClass $reflection
     * @param array $interfaces
     * @return array
     */
    public function getImports(ReflectionClass $reflection, array $interfaces): array
    {
        $content = explode(PHP_EOL, file_get_contents($reflection->getFileName()));
        foreach ($content as $key => $value) {
            if ($key >= $reflection->getStartLine()) {
                break;
            }
            if (empty($content[$key]) || !preg_match('/^use.*;$/', trim($content[$key]))) {
                continue;
            }
            if (in_array(trim($content[$key]), $interfaces)) {
                continue;
            }
            $interfaces[] = trim($content[$key]);
        }
        return $interfaces;
    }


    /**
     * @param ReflectionClass $reflection
     * @param array $interfaces
     * @return array
     */
    public function getTraits(ReflectionClass $reflection, array $interfaces): array
    {
        $traits = [];
        foreach ($reflection->getTraits() as $class) {
            if (!in_array('use ' . $class->getName() . ';', $interfaces)) {
                $interfaces[] = 'use ' . $class->getName() . ';';
            }
            $data     = explode('\\', $class->getName());
            $traits[] = '
    use ' . end($data) . ';';
        }
        return [$interfaces, $traits];
    }


    /**
     * @param ReflectionClass $reflection
     * @param array $interfaces
     * @param array $filters
     * @return array
     */
    public function getInterfaces(ReflectionClass $reflection, array $interfaces, array $filters = []): array
    {
        $names = [];
        foreach ($reflection->getInterfaces() as $value) {
            if (in_array($value->getName(), $interfaces) || in_array($value->getName(), $filters)) {
                continue;
            }
            if (!in_array('use ' . $value->getName() . ';', $interfaces)) {
                $interfaces[] = 'use ' . $value->getName() . ';';
            }
            $data    = explode('\\', $value->getName());
            $names[] = end($data);
        }
        return [$interfaces, $names];
    }


    /**
     * @param ReflectionClass $reflection
     * @param array $interfaces
     * @param array $filters
     * @return array
     */
    public function getOldMethods(ReflectionClass $reflection, array $interfaces, array $filters = []): array
    {
        $oldMethods   = [];
        $content      = explode(PHP_EOL, file_get_contents($reflection->getFileName()));
        $traitMethods = $this->getTraitMethods($reflection);
        foreach ($reflection->getMethods() as $method) {
            if ($method->getDeclaringClass()->getName() != $reflection->getName()) {
                continue;
            }
            if (in_array($method->getName(), $filters) || in_array($method->getName(), $traitMethods)) {
                continue;
            }

            $data = $this->getFuncLineContent($content, $method->getStartLine(), $method->getEndLine());
            $data = preg_replace('/[^(]#\[.*\]/', '', $data);
            [$interfaces, $attributes] = $this->getAttributes($method, $interfaces);
            $oldMethods[] = "
    " . $method->getDocComment() . implode($attributes) . PHP_EOL . $data;
        }

        return [$interfaces, $oldMethods];
    }


    /**
     * @param ReflectionClass $reflection
     * @return array
     */
    protected function getTraitMethods(ReflectionClass $reflection): array
    {
        $methods = [];
        foreach ($reflection->getTraits() as $class) {
            foreach ($class->getMethods() as $reflectionMethod) {
                $methods[] = $reflectionMethod->getName();
            }
        }
        return $methods;
    }


    /**
     * @param string $table
     * @param string $append
     * @return string
     */
    public function clearXiaHuaXian(string $table, string $append = ''): string
    {
        $class = explode('_', $table);
        if (!empty($append)) {
            $class[] = $append;
        }
        $class = array_map(function ($data) {
            return ucfirst($data);
        }, $class);

        return implode($class);
    }


    /**
     * @param array $data
     * @return int
     */
    public function maxLength(array $data): int
    {
        $length = 0;
        foreach ($data as $datum) {
            $_length = mb_strlen($datum['Field']);
            if ($_length > $length) {
                $length = $_length;
            }
        }
        return $length;
    }


    /**
     * @param array $data
     * @return int
     */
    public function maxStringLength(array $data): int
    {
        $length = 0;
        foreach ($data as $key => $datum) {
            $_length = mb_strlen($key);
            if ($_length > $length) {
                $length = $_length;
            }
        }
        return $length;
    }

    /**
     * @param array $explode
     * @param int $start
     * @param int $end
     * @return string
     */
    public function getFuncLineContent(array $explode, int $start, int $end): string
    {
        $exists = array_slice($explode, $start - 1, $end - $start + 1);
        return implode(PHP_EOL, $exists);
    }


    /**
     * @param ReflectionClass $reflection
     * @param $interfaces
     * @return array
     */
    protected function resetProperty(ReflectionClass $reflection, $interfaces): array
    {
        $properties = [];
        foreach ($reflection->getProperties() as $property) {
            if ($property->getDeclaringClass()->getName() != $reflection->getName()) {
                continue;
            }
            if (in_array($property->getName(), ['primary', 'table', 'connection'])) {
                continue;
            }
            if ($property->getType() instanceof \ReflectionUnionType) {
                $types = [];
                foreach ($property->getType()->getTypes() as $type) {
                    $types[] = $type->getName();
                }
                $type = implode('|', $types);
            } else {
                $type = $property->getType()->getName();
            }

            $pHtml = empty($property->getDocComment()) ? '' : '
    ' . $property->getDocComment();
            if (count($property->getAttributes()) > 0) {
                [$interfaces, $attributes] = $this->getAttributes($property, $interfaces);
                $pHtml .= implode($attributes) . '
    ' . $this->prefix($property) . ' ' . ($property->isStatic() ? 'static ' : '') . $type . ' $' . $property->getName();
            } else {
                $pHtml = '
    ' . $this->prefix($property) . ' ' . ($property->isStatic() ? 'static ' : '') . $type . ' $' . $property->getName();
            }

            if ($property->hasDefaultValue()) {
                $pHtml .= ' = ' . (is_string($property->getDefaultValue()) ? '\'' . $property->getDefaultValue() . '\'' : json_encode($property->getDefaultValue(), JSON_UNESCAPED_UNICODE));
            }
            $properties[] = $pHtml . ';' . PHP_EOL . PHP_EOL;
        }
        return [$interfaces, $properties];
    }


    /**
     * @param ReflectionClass|\ReflectionMethod|\ReflectionProperty $property
     * @param array $interfaces
     * @return array
     * 获取注解
     */
    protected function getAttributes(ReflectionClass|\ReflectionMethod|\ReflectionProperty $property, array $interfaces): array
    {
        $attributes = [];
        foreach ($property->getAttributes() as $attribute) {
            $arguments = [];
            if (!in_array('use ' . $attribute->getName() . ';', $interfaces)) {
                $interfaces[] = 'use ' . $attribute->getName() . ';';
            }
            foreach ($attribute->getArguments() as $key => $argument) {
                if (is_string($argument)) {
                    if (class_exists($argument)) {
                        $interfaces[] = 'use ' . $argument . ';';

                        $end = explode('\\', $argument);

                        $arguments[] = (is_string($key) ? $key . ': ' : '') . end($end) . '::class';
                    } else {
                        $arguments[] = (is_string($key) ? $key . ': ' : '') . '\'' . $argument . '\'';
                    }
                } else if (is_object($argument)) {
                    $class        = get_class($argument);
                    $interfaces[] = 'use ' . $class . ';';

                    $end = explode('\\', $class);

                    $arguments[] = (is_string($key) ? $key . ': ' : '') . end($end) . '::' . get_object_vars($argument)['name'];
                } else {
                    $arguments[] = (is_string($key) ? $key . ': ' : '') . $argument;
                }
            }

            $end = explode('\\', $attribute->getName());

            $attributes[] = '
    #[' . end($end) . (empty($arguments) ? '' : '(' . implode(', ', $arguments) . ')') . ']';
        }
        return [$interfaces, $attributes];
    }


    /**
     * @param $property
     * @return string
     */
    protected function prefix($property): string
    {
        return $property->isPublic() ? 'public' : ($property->isProtected() ? 'protected' : 'private');
    }

}